<template>
  <div>
    <el-card class="selector-card">
      <div class="header-container">
        <div class="header-top">
          <el-text style="white-space: nowrap" tag="b" size="large">{{ $t('message.random.loraManager') }}</el-text>
        </div>

        <!-- 文件夹筛选器 - 横向标签布局 -->
        <div class="folder-filters">
          <!-- 一级文件夹标签 -->
          <div class="folder-level" v-if="grandparentFolders.length > 0">
            <el-text class="level-label">{{ $t('message.random.Category') + ":" }}</el-text>
            <div class="folder-tags">
              <el-tag v-for="folder in grandparentFolders" :key="folder.name"
                :type="selectedGrandparent === folder.name ? 'primary' : 'info'" size="default" class="folder-tag"
                @click="selectGrandparent(folder)">
                {{ folder.name }}
                <span class="folder-count">({{ folder.loraCount }})</span>
              </el-tag>
            </div>
          </div>

          <!-- 二级文件夹标签 -->
          <div v-if="selectedGrandparent && parentFolders.length > 0" class="folder-level">
            <el-text class="level-label">{{ $t('message.random.SubFolder') + ":" }}</el-text>
            <div class="folder-tags">
              <el-tag v-for="subfolder in parentFolders" :key="subfolder.name"
                :type="selectedParent === subfolder.name ? 'primary' : 'info'" size="default" class="folder-tag"
                @click="selectParent(subfolder)">
                {{ subfolder.name }}
                <span class="folder-count">({{ subfolder.loraCount }})</span>
              </el-tag>
            </div>
          </div>

          <!-- 显示当前筛选状态 -->
          <div class="current-filters" v-if="selectedGrandparent || selectedParent">
            <el-tag type="info" size="medium" closable @close="clearFilters">
              <el-icon>
                <Filter />
              </el-icon>
              当前筛选:
              <span v-if="selectedGrandparent">{{ selectedGrandparent }}</span>
              <span v-if="selectedParent"> / {{ selectedParent }}</span>
            </el-tag>
          </div>
        </div>
        <div style="display: flex;">
          <el-select-v2 style="width: 50%; " size="default" v-model="selectedLoraName" :options="filteredLoraOptions"
            :filter-method="handleFilter" filterable value-key="value" :placeholder="$t('message.common.search')"
            @change="handleLoraSelect">
            <template #default="{ item }">
              <div>
                <el-popover placement="right" :width="380" trigger="hover" :disabled="!item.data.lora_image">
                  <template #reference>
                    <div style="display: flex; align-items: center;">
                      <div v-if="item.data.lora_image" class="option-thumbnail">
                        <el-image style="height: 30px;object-fit: contain;"
                          :src="getLocalImageUrl(item.data.lora_image)" fit="contain" />
                      </div>
                      <div class="option-text">
                        <el-text>{{ item.label }}</el-text>
                      </div>
                    </div>
                  </template>
                  <div class="preview-container">
                    <el-image v-if="item.data.lora_image" :src="getLocalImageUrl(item.data.lora_image)" fit="contain"
                      style="height: 200px; width: auto; object-fit: contain" />
                    <div v-else class="no-preview">
                      <el-icon :size="40"><ele-Picture /></el-icon>
                      <el-text>{{ $t('message.random.noImage') }}</el-text>
                    </div>
                    <div class="lora-info">
                      <el-text tag="b">{{ $t('message.common.name') }}</el-text>
                      <el-text>{{ item.data.lora_name }}</el-text>
                      <div v-if="item.data.parent_folder">
                        <el-text tag="b">{{ $t('message.random.Category') }}:</el-text>
                        <el-text>{{ item.data.parent_folder }}</el-text>
                      </div>
                      <div v-if="item.data.grandparent_folder">
                        <el-text tag="b">{{ $t('message.random.CompletePath') }}</el-text>
                        <el-text>{{ item.data.grandparent_folder }}</el-text>
                      </div>
                      <div v-if="item.data.lora_path">
                        <el-text tag="b">{{ $t('message.random.CompletePath') }}:</el-text>
                        <el-text style="font-size: 12px; opacity: 0.7;">{{ item.data.lora_path }}</el-text>
                      </div>
                    </div>
                  </div>
                </el-popover>
              </div>
            </template>
          </el-select-v2>
          <el-button class="ml10" type="primary" size="default" @click="refreshLoraList" :loading="loading">
            <el-icon>
              <Refresh />
            </el-icon>
            {{ $t('message.common.refresh') }}
          </el-button>
        </div>
      </div>
    </el-card>

    <div class="lora-list-container">
      <div class="list-header">
        <el-text class="list-title">{{ $t('message.random.loraApply') + ':\t' + exPrompt.loraList.length }}</el-text>
      </div>

      <div v-if="exPrompt.loraList.length === 0" class="empty-list">
        <el-empty :description="$t('message.random.noLora')">
          <el-text type="info">{{ $t('message.random.selectLora') }}</el-text>
        </el-empty>
      </div>

      <!-- 修改为纵向排列的网格布局 -->
      <div v-else class="lora-grid">
        <el-card v-for="(lora, index) in exPrompt.loraList" :key="index" class="lora-card">
          <div class="card-header">
            <el-text class="item-name" truncated>{{ lora.lora_label }}</el-text>
          </div>

          <div class="card-content">
            <div class="image-section">
              <el-image class="lora-image" :src="getLocalImageUrl(lora.lora_image)" fit="contain" />
              <div class="controls-section" >
                <div class="strength-controls">
                  <el-popover trigger="hover" :width="250" placement="top">
                    <template #reference>
                      <el-input-number v-model="lora.strength_model" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" class="control-item" />
                    </template>
                    <div style="padding: 10px;">
                      <el-slider v-model="lora.strength_model" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" :marks="{ 0.5: 'model' }" />
                    </div>
                  </el-popover>

                  <el-popover trigger="hover" :width="250" placement="top">
                    <template #reference>
                      <el-input-number v-model="lora.strength_clip" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" class="control-item" />
                    </template>
                    <div style="padding: 10px;">
                      <el-slider v-model="lora.strength_clip" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" :marks="{ 0.5: 'clip' }" />
                    </div>

                  </el-popover>
                </div>

                <div class="action-buttons">
                  <el-button type="danger" @click="removeLora(lora.lora_name)" size="default" class="action-btn"
                    icon="ele-Delete">
                  </el-button>

                  <el-button type="primary" @click="saveLoraConfig(lora.lora_name, lora)" size="default"
                    class="action-btn" icon="ele-Check">
                  </el-button>

                  <el-upload action="" :show-file-list="false" :before-upload="(file) => beforeImageUpload(file, lora)"
                    accept="image/*">
                    <el-button type="primary" size="default" class="action-btn" icon="ele-Upload">
                    </el-button>
                  </el-upload>

                  <el-button class="action-btn" type="primary" size="default" @click="getLoraMetaData(lora.lora_name)"
                    icon="ele-View">
                  </el-button>
                </div>
              </div>
            </div>
            <div class="tags-section">
              <el-input v-stop-comfy-events type="textarea" v-model="lora.tags" :placeholder="$t('message.random.tags')"
                :autosize="{ minRows: 4, maxRows: 15 }" resize="none" class="tags-input" />
            </div>
          </div>
        </el-card>
      </div>
    </div>

    <!-- 元数据弹窗 -->
    <el-dialog v-model="metadataDialogVisible" append-to-body width="60%">
      <el-scrollbar style="height: 500px;">
        <el-tabs v-model="activeName">
          <el-tab-pane label="Lora" name="first">
            <div class="metadata-container" v-loading="state.isLoading">
              <div class="metadata-section" style="display: flex;">
                <el-image style="height: 100px;object-fit: contain;" hide-on-click-modal fit="contain"
                  :src="getLocalImageUrl(state.chooseLora.lora_image)"
                  :preview-src-list="[getLocalImageUrl(state.chooseLora.lora_image)]"></el-image>
                <div class="ml10">
                  <el-row class="mb10"><el-text>{{ state.chooseLora.lora_name }}</el-text></el-row>
                  <el-row class="mb10"><el-text>{{ state.metadata['sha256'] }}</el-text></el-row>
                </div>
              </div>

              <div class="metadata-section" v-if="state.metadata['ss_tag_frequency']">
                <el-scrollbar style="height: 300px; margin-top: 10px;">
                  <div v-if="state.tagFrequency.length > 0" class="metadata-section">
                    <div class="tag-cloud">
                      <el-tag v-for="(tagItem, index) in state.tagFrequency" :key="index" class="tag-item">
                        {{ tagItem.tag }}
                        <span class="tag-frequency">({{ tagItem.frequency }})</span>
                      </el-tag>
                    </div>
                  </div>
                  <div v-else>
                    <el-text>No tag frequency data available.</el-text>
                  </div>
                </el-scrollbar>

                <div class="tag-selection">
                  <el-slider v-model="state.chooseCount" :min="0" :max="state.tagFrequency.length" :step="1"
                    @change="handleChooseCount" />
                  <el-text>选择前 {{ state.chooseCount }} 个标签</el-text>
                  <el-input v-stop-comfy-events type="textarea" :autosize="{ minRows: 3, maxRows: 15 }"
                    v-model="state.metadataTags" placeholder="选中的标签将显示在这里" class="mt10" />
                </div>
              </div>

              <div class="metadata-section" v-else>
                <el-text>此Lora模型没有可用的元数据</el-text>
              </div>
            </div>
          </el-tab-pane>
          <el-tab-pane label="Civitai" name="second">
            <div class="metadata-container" v-loading="state.civitalLoading">
              <el-tooltip 
                v-for="tag in state.civitaiInfo.wordArray" 
                :key="tag"
                :content="tag"
                placement="top"
              >
                <el-tag 
                  class="mb10 tag-long-text" 
                  @click="handleCopyTag(tag)" 
                  type="primary"
                >
                  {{ tag }}
                </el-tag>
              </el-tooltip>
              <div style="display: flex;gap: 10px;flex-direction: column;">
                <div style="display: flex;gap: 10px;" v-for="image in state.civitaiInfo.images">
                  <img style="max-height: 200px; max-width: 100px; object-fit: contain;"
                    :src="imageStates[image.id].currentUrl" :alt="`CivitAI Image ${image.hash}`" loading="lazy"
                    crossOrigin="anonymous" @load="(e) => handleImageLoad(e, image)"
                    @error="(e) => handleImageError(e, image)" />
                  <el-text v-if="image.meta">{{ image.meta.prompt }}</el-text>
                </div>
              </div>
            </div>
          </el-tab-pane>
          <el-tab-pane label="Config" name="third">
            <div class="metadata-container">
              <div class="config-section">
                <!-- 强度控制区域 -->
                <div class="strength-controls config-controls">
                  <el-popover trigger="hover" :width="250" placement="top">
                    <template #reference>
                      <div class="control-group">
                        <el-text tag="b">{{ $t('message.random.modelStrength') }}:</el-text>
                        <el-input-number v-model="state.loraConfig.strength_model" :min="-1" :max="2" :step="0.1"
                          size="default" controls-position="right" class="control-item" />
                      </div>
                    </template>
                    <div style="padding: 10px;">
                      <el-slider v-model="state.loraConfig.strength_model" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" :marks="{ 0.5: 'model' }" />
                    </div>
                  </el-popover>

                  <el-popover trigger="hover" :width="250" placement="top">
                    <template #reference>
                      <div class="control-group">
                        <el-text tag="b">{{ $t('message.random.clipStrength') }}:</el-text>
                        <el-input-number v-model="state.loraConfig.strength_clip" :min="-1" :max="2" :step="0.1"
                          size="default" controls-position="right" class="control-item" />
                      </div>
                    </template>
                    <div style="padding: 10px;">
                      <el-slider v-model="state.loraConfig.strength_clip" :min="-1" :max="2" :step="0.1" size="default"
                        controls-position="right" :marks="{ 0.5: 'clip' }" />
                    </div>
                  </el-popover>
                </div>

                <div class="tags-section config-tags">
                  <el-text tag="b" class="tags-label">{{ $t('message.random.activationText') }}:</el-text>
                  <el-input v-stop-comfy-events type="textarea" v-model="state.loraConfig['activation text']"
                    :placeholder="$t('message.random.enterActivationText')" :autosize="{ minRows: 4, maxRows: 15 }"
                    resize="none" class="tags-input" />
                </div>

                <div class="config-actions">
                  <el-button type="primary" @click="saveCurrentLoraConfig" size="default" :loading="state.configSaving">
                    <el-icon><ele-Check /></el-icon>
                    {{ $t('message.common.save') }}
                  </el-button>
                </div>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </el-scrollbar>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, reactive, watch } from 'vue';
import { ElMessage } from 'element-plus';
import { useExPrompt } from '@renderer/stores/useExPrompt';
import { useConfigStore } from '@renderer/stores/configStore';
import { ipcService } from '@renderer/services/ipcService';

// 文件夹筛选相关状态
const selectedGrandparent = ref('');
const selectedParent = ref('');
const grandparentFolders = ref<EnhancedFolderNode[]>([]);
const parentFolders = ref<EnhancedFolderNode[]>([]);
const metadataDialogVisible = ref(false);
const activeName = ref('first')

// 增强文件夹节点类型，包含Lora数量
interface EnhancedFolderNode {
  name: string;
  path: string;
  children: EnhancedFolderNode[];
  loraCount: number;
}

interface CivitaiImage {
  url: string;
  meta: Meta;
  id: string;
  hash: string;
}

interface Meta {
  prompt: string,
}

interface LoraConfig {
  strength_model?: number;
  strength_clip?: number;
  "activation text"?: string;
  [key: string]: any;
}

// 组件状态
const state = reactive({
  loraInfoList: [] as LoraInfo[],
  folderStructure: [] as FolderNode[],
  metadata: {} as Record<string, any>,
  isLoading: false,
  tagFrequency: [] as Array<{ tag: string, frequency: number }>,
  metadataTags: '',
  chooseCount: 10,
  chooseLora: {} as Lora,
  sha256: '',
  chooseLoraPath: '',
  civitaiInfo: {
    trainedWords: '',
    images: [] as CivitaiImage[],
    wordArray: [] as string[]
  },
  loraConfig: {
    strength_model: 1,
    strength_clip: 1,
    "activation text": ""
  } as LoraConfig,
  configSaving: false,
  civitalLoading: false,
  metadataLoading: false,
});

const loading = ref(false);
const selectedLoraName = ref('');
const filterInput = ref('');
const exPrompt = useExPrompt();
const configStore = useConfigStore();

// 计算过滤后的Lora选项
const filteredLoraOptions = computed(() => {
  let options = state.loraInfoList.map(item => ({
    value: item.lora_path,
    label: item.lora_name,
    data: item
  }));

  // 应用文件夹筛选
  if (selectedGrandparent.value) {
    options = options.filter(option => {
      // 匹配一级目录
      const isInGrandparent =
        option.data.grandparent_folder === selectedGrandparent.value ||
        (!option.data.grandparent_folder &&
          option.data.parent_folder === selectedGrandparent.value);

      // 如果有二级目录筛选
      if (selectedParent.value) {
        return isInGrandparent &&
          option.data.parent_folder === selectedParent.value;
      }
      return isInGrandparent;
    });
  }

  // 根据输入框过滤
  if (filterInput.value) {
    const search = filterInput.value.toLowerCase();
    options = options.filter(option =>
      option.label.toLowerCase().includes(search) ||
      (option.data.parent_folder && option.data.parent_folder.toLowerCase().includes(search)) ||
      (option.data.grandparent_folder && option.data.grandparent_folder.toLowerCase().includes(search))
    );
  }

  return options;
});

// 选择一级文件夹
const selectGrandparent = (folder: EnhancedFolderNode) => {
  if (selectedGrandparent.value === folder.name) {
    // 如果已经选中，则取消选择
    selectedGrandparent.value = '';
    selectedParent.value = '';
    parentFolders.value = [];
  } else {
    selectedGrandparent.value = folder.name;
    selectedParent.value = '';
    parentFolders.value = folder.children;
  }
};

// 选择二级文件夹
const selectParent = (subfolder: EnhancedFolderNode) => {
  if (selectedParent.value === subfolder.name) {
    // 如果已经选中，则取消选择
    selectedParent.value = '';
  } else {
    selectedParent.value = subfolder.name;
  }
};

// 清除所有筛选
const clearFilters = () => {
  selectedGrandparent.value = '';
  selectedParent.value = '';
  parentFolders.value = [];
};

// 获取Lora列表
const getLoraList = async () => {
  loading.value = true;
  try {
    const result = await ipcService.scanLoras(configStore.config.loraPath);
    if (result.success) {
      state.loraInfoList = result.data.loras;
      state.folderStructure = result.data.folderStructure;

      // 增强文件夹节点，添加Lora数量统计
      grandparentFolders.value = enhanceFolderNodes(
        state.folderStructure,
        state.loraInfoList
      );
    } else {
      ElMessage.error('加载Lora失败: ' + result.message);
    }
  } catch (error) {
    console.error('IPC获取lora失败:', error);
    ElMessage.error("Lora列表加载失败，请检查配置路径");
  } finally {
    loading.value = false;
  }
};

// 增强文件夹节点，添加Lora数量统计
const enhanceFolderNodes = (
  folders: FolderNode[],
  loras: LoraInfo[]
): EnhancedFolderNode[] => {
  return folders.map(folder => {
    // 计算当前文件夹下的Lora数量
    const loraCount = loras.filter(lora =>
      lora.grandparent_folder === folder.name ||
      (!lora.grandparent_folder && lora.parent_folder === folder.name)
    ).length;

    // 递归处理子文件夹
    const children = folder.children.map(subfolder => {
      const subLoraCount = loras.filter(lora =>
        lora.grandparent_folder === folder.name &&
        lora.parent_folder === subfolder.name
      ).length;

      return {
        ...subfolder,
        loraCount: subLoraCount,
        children: []
      };
    });

    return {
      ...folder,
      loraCount,
      children
    };
  });
};

// 刷新Lora列表
const refreshLoraList = () => {
  state.loraInfoList = [];
  clearFilters();
  getLoraList();
};

// 处理选择器变化
const handleLoraSelect = (value: string) => {
  addLora(value)
};

// 添加Lora
const addLora = async (loraPath: string) => {
  if (!loraPath) {
    ElMessage.warning('请选择有效的Lora模型');
    return;
  }

  // 检查是否已存在
  const exists = exPrompt.loraList.some(lora => lora.lora_name === loraPath);
  if (exists) {
    ElMessage.warning(`Lora模型已存在`);
    return;
  }

  // 查找对应的 Lora 信息
  const loraInfo = state.loraInfoList.find(lora => lora.lora_path === loraPath);
  if (!loraInfo) {
    ElMessage.error('找不到对应的Lora信息');
    return;
  }

  // 1. 先使用默认配置立即添加到列表，避免空窗期
  const defaultConfig = {
    strength_model: 1,
    strength_clip: 1,
    tags: '',
    isLoadingConfig: true  // 添加加载状态标记
  };

  // 添加到列表
  const newLoraIndex = exPrompt.loraList.length;
  exPrompt.loraList.push({
    lora_name: loraInfo.lora_path,
    lora_image: loraInfo.lora_image,
    strength_model: defaultConfig.strength_model,
    strength_clip: defaultConfig.strength_clip,
    lora_config: loraInfo.lora_config,
    lora_label: loraInfo.lora_name,
    tags: defaultConfig.tags,
    parent_folder: loraInfo.parent_folder,
    grandparent_folder: loraInfo.grandparent_folder,
    isLoadingConfig: true  // 标记为配置加载中
  });
  
  selectedLoraName.value = '';
  ElMessage.success(`已添加: ${loraInfo.lora_name}，正在加载配置...`);

  // 2. 异步加载配置，不阻塞UI
  try {
    // 显示加载指示器（可以在UI中绑定isLoadingConfig显示加载动画）
    const configResult = await ipcService.getLoraConfig(loraInfo.lora_path);
    
    if (configResult.success) {
      // 找到刚才添加的Lora并更新配置
      const addedLora = exPrompt.loraList.find(
        lora => lora.lora_name === loraInfo.lora_path
      );
      
      if (addedLora) {
        // 更新配置
        if (configResult.data['activation text'] && configResult.data['activation text'] !== '') {
          addedLora.tags = configResult.data['activation text'];
        }
        if (configResult.data['preferred weight'] && configResult.data['preferred weight'] !== 0) {
          addedLora.strength_model = configResult.data['preferred weight'];
        }
        if (configResult.data.strength_clip && configResult.data.strength_clip !== 0) {
          addedLora.strength_clip = configResult.data.strength_clip;
        }
        
        // 隐藏加载状态
        addedLora.isLoadingConfig = false;
        ElMessage.success(`${loraInfo.lora_name} 配置加载完成`);
      }
    }
  } catch (error) {
    console.error('获取Lora配置失败:', error);
    // 即使配置加载失败，也隐藏加载状态
    const addedLora = exPrompt.loraList.find(
      lora => lora.lora_name === loraInfo.lora_path
    );
    if (addedLora) {
      addedLora.isLoadingConfig = false;
    }
    ElMessage.warning(`配置加载失败，使用默认值: ${error instanceof Error ? error.message : '未知错误'}`);
  }
};

const saveLoraConfig = async (loraPath: string, data: Lora) => {
  try {
    if (loraPath) {
      const config = {
        "preferred weight": data.strength_model,
        strength_clip: data.strength_clip,
        "activation text": data.tags
      };
      const result = await ipcService.saveLoraConfig(loraPath, config)
      if (result.success) {
        ElMessage.success("Lora预设保存成功")
      }
      else {
        ElMessage.error("Lora预设保存失败:\t" + result.message)
      }
    }
    else {
      ElMessage.error("Lora路径不能为空")
    }
  }
  catch (error) {
    ElMessage.error(JSON.stringify(error))
  }
}



const saveCurrentLoraConfig = async () => {
  try {
    // 检查是否有选中的Lora路径
    if (!state.chooseLoraPath) {
      ElMessage.warning("请先选择Lora模型");
      return;
    }

    // 显示加载状态
    state.configSaving = true;

    // 构造配置对象，与现有saveLoraConfig保持一致的结构
    const config = {
      "preferred weight": state.loraConfig.strength_model ?? 1,
      strength_clip: state.loraConfig.strength_clip ?? 1,
      "activation text": state.loraConfig["activation text"] ?? ""
    };

    // 调用IPC服务保存配置
    const result = await ipcService.saveLoraConfig(state.chooseLoraPath, config);
    
    if (result.success) {
      ElMessage.success("Lora预设保存成功");
      
      // 同步更新列表中对应Lora的配置
      const targetLora = exPrompt.loraList.find(
        item => item.lora_name === state.chooseLoraPath
      );
      if (targetLora) {
        targetLora.strength_model = config["preferred weight"];
        targetLora.strength_clip = config.strength_clip;
        targetLora.tags = config["activation text"];
      }
    } else {
      ElMessage.error(`Lora预设保存失败: ${result.message}`);
    }
  } catch (error) {
    console.error("保存Lora配置时发生错误:", error);
    ElMessage.error(`保存失败: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
  } finally {
    state.configSaving = false;
  }
};

// 获取lora元数据
const getLoraMetaData = async (loraPath: string) => {
  state.isLoading = true
  metadataDialogVisible.value = true;
  const requestedPath = loraPath;
  try {
    state.metadata = {}
    state.tagFrequency = []
    state.chooseCount = 10
    state.metadataTags = ''
    state.chooseLoraPath = loraPath;
    const result = await ipcService.getLoraMetadata(loraPath);
    if (requestedPath != state.chooseLoraPath) {
      console.log(`忽略过期请求结果：${requestedPath}（当前处理：${state.chooseLoraPath}）`);
      return;
    }
    if (result.success ) {
      state.metadata = result.metadata
      state.sha256 = state.metadata['sha256']
      const exists = state.loraInfoList.find(lora => lora.lora_path === loraPath);
      if (exists) {
        Object.assign(state.chooseLora, exists)
      }
      // 处理标签频率数据
      if (result.metadata['ss_tag_frequency']) {
        try {
          const tagFrequency = JSON.parse(result.metadata['ss_tag_frequency']);
          const firstKey = Object.keys(tagFrequency)[0];
          const tags = tagFrequency[firstKey];

          state.tagFrequency = Object.entries(tags)
            .map(([tag, frequency]) => ({ tag, frequency: frequency as number }))
            .sort((a, b) => b.frequency - a.frequency);

          handleChooseCount(10); // 默认选择前10个标签
        } catch (e) {
          console.error('解析标签频率失败:', e);
        }
      }
    }
    else {
      ElMessage.error(JSON.stringify(result))
    }
  }
  catch (error) {
    ElMessage.error("获取lora元数据失败")
  }
  finally {
    if (requestedPath == state.chooseLoraPath) {
      state.isLoading = false;
    }
  }
}

const imageStates = ref<Record<string, { currentUrl: string; isSource: boolean }>>({});

const getLocalCivitaiImageUrl = (image: CivitaiImage) => {
  if (!image.url) return '';
  const urlSegments = image.url.split('/');
  let url = urlSegments.filter(segment => segment).pop() || '';
  url = configStore.config.imagesPath + '\\CivitaiCache\\' + url.split('.')[0] + '.webp';
  return configStore.comfyProxyImage(`file://${url}`);
}

const handleImageLoad = async (e: Event, image: CivitaiImage) => {
  const imgState = imageStates.value[image.id];
  if (!imgState.isSource) return;

  try {
    const imgElement = e.target as HTMLImageElement;

    // 1. 确保图片完全加载
    if (!imgElement.complete || !imgElement.naturalWidth) {
      throw new Error('图片未完全加载，无法处理');
    }

    // 2. 创建 canvas 并绘制原始图片（不进行压缩和格式转换）
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    if (!ctx) throw new Error('canvas 初始化失败');

    // 保持原始尺寸
    canvas.width = imgElement.naturalWidth;
    canvas.height = imgElement.naturalHeight;
    ctx.drawImage(imgElement, 0, 0);

    // 3. 从 canvas 获取原始图像数据（不指定格式，保持原始质量）
    const blob = await new Promise<Blob>((resolve, reject) => {
      canvas.toBlob(
        (result) => {
          if (result) resolve(result);
          else reject(new Error('canvas 转换为 Blob 失败'));
        }
        // 不指定格式和质量参数，使用默认值
      );
    });

    // 4. 将 Blob 转换为 File 对象（后端需要的类型）
    // 提取原始文件名
    const urlSegments = image.url.split('/');
    const fileName = urlSegments.filter(segment => segment).pop() || `image-${Date.now()}`;
    const file = new File([blob], fileName, { type: blob.type });

    // 5. 构建缓存路径（供后端使用）
    const cachePath = configStore.config.imagesPath + '\\CivitaiCache\\' + fileName;

    // 6. 调用 IPC 传递 File 对象给后端
    const cacheResult = await ipcService.cacheImage(cachePath, file);
    if (!cacheResult.success) {
      ElMessage.error(`缓存异常：${cacheResult.message}`);
    }

  } catch (err: any) {
    console.error('获取图片内容失败：', err);
    ElMessage.error(`缓存异常：${err.message}`);
  }
};


const handleImageError = (e: Event, image: CivitaiImage) => {
  const imgState = imageStates.value[image.id];
  if (!imgState.isSource) {
    imgState.currentUrl = image.url;
    imgState.isSource = true;
  } else {
    // 源地址失败→兜底图
    imgState.currentUrl = '/static/images/default-error.png';
  }
};

watch(() => state.sha256, async (newval) => {
  if (newval) {
    const currentSha = newval;
    const currentLoraPath = state.chooseLoraPath;
    state.civitalLoading = true
    state.civitaiInfo = { trainedWords: '', images: [],wordArray: [] };
    imageStates.value = {};
    state.loraConfig = {};
    try {
      ipcService.getLoraConfig(state.chooseLoraPath).then((res) => {
        if (state.sha256 === currentSha && state.chooseLoraPath === currentLoraPath) {
          // 合并配置并确保默认值存在
          state.loraConfig = {
            strength_model: 1,
            strength_clip: 1,
            "activation text": "",
            ...res.data
          };
        }
      }).catch((err) => {
        ElMessage.error(`获取Lora配置失败: ${err.message || '未知错误'}`);
      });
      const metadataRes = await ipcService.getCivitaiMetadata(
        currentSha,
        currentLoraPath,
        false
      );
      if (state.sha256 !== currentSha || state.chooseLoraPath !== currentLoraPath) {
        return;
      }
      const { images: rawImages, ...restCivitaiInfo } = metadataRes.data;
      const handledImages: CivitaiImage[] = rawImages.map((rawImg) => ({
        id: rawImg.hash,
        ...rawImg,
        meta: rawImg.meta || { prompt: '未获取到提示词' },
      }));
      handledImages.forEach((image) => {
        imageStates.value[image.id] = {
          currentUrl: getLocalCivitaiImageUrl(image),
          isSource: false,
        };
      });

      state.civitaiInfo = {
        ...restCivitaiInfo,
        images: handledImages,
      };
      if (state.civitaiInfo.trainedWords) {
        try {
          // 先检查类型，如果已经是数组则直接赋值
          if (Array.isArray(state.civitaiInfo.trainedWords)) {
            state.civitaiInfo.wordArray = state.civitaiInfo.trainedWords as string[];
          }
        } catch (err) {
          console.error('解析trainedWords失败:', err);
          console.error('原始值:', state.civitaiInfo.trainedWords);
          console.error('原始值类型:', typeof state.civitaiInfo.trainedWords);
          state.civitaiInfo.wordArray = [JSON.stringify(state.civitaiInfo.trainedWords)];
        }
      }
      ElMessage.info(metadataRes.message || '元数据加载成功');
    } catch (err: any) {
      if (state.sha256 === currentSha) {
        ElMessage.error(`获取元数据失败：${err.message || '未知错误'}`);
      }
    } finally {
      if (state.sha256 === currentSha) {
        state.civitalLoading = false;
      }
    }
  }
  else return
})

const handleFilter = (val: string) => {
  filterInput.value = val;
};

// 删除Lora
const removeLora = (loraName: string) => {
  exPrompt.loraList = exPrompt.loraList.filter(
    lora => lora.lora_name !== loraName
  );
  ElMessage.success(`已移除: ${loraName}`);
};

// 获取本地图片URL
const getLocalImageUrl = (url: string | null) => {
  if (!url) return '';
  return configStore.comfyProxyImage(`file://${url}`);
};

const beforeImageUpload = async (file: File, lora: Lora) => {
  try {
    const result = await ipcService.saveLoraImage(
      file,
      lora.lora_name
    );

    if (result.success) {
      ElMessage.success('封面保存成功');
      configStore.updateImageVersion(lora.lora_image)
    } else {
      ElMessage.error(`保存失败: ${result.message}`);
    }
  } catch (error) {
    ElMessage.error('上传封面时出错');
    console.error('封面上传错误:', error);
  }

  return false;
};

const handleChooseCount = (value: number) => {
  const count = Math.max(0, Math.min(value, state.tagFrequency.length));
  const selectedTags = state.tagFrequency
    .slice(0, count)
    .map(item => item.tag);
  state.metadataTags = selectedTags.join(', ');
}

const handleCopyTag = (tag:string)=>{
  navigator.clipboard
    .writeText(tag)
    .then(() => ElMessage.success('内容已复制'))
    .catch(() => ElMessage.error('复制失败'))
}


onMounted(() => {
  getLoraList();
});

defineExpose({
  addLora,
  getLoraMetaData,
  removeLora
})

// 类型定义
interface LoraInfo {
  lora_name: string
  lora_config: string
  lora_image: string | null
  lora_path: string
  parent_folder: string
  grandparent_folder: string
}

interface FolderNode {
  name: string;
  path: string;
  children: FolderNode[];
}

interface Lora {
  lora_name: string
  lora_image: string | null
  strength_model: number
  strength_clip: number
  lora_label: string
  lora_config: string
  tags: string
  parent_folder?: string
  grandparent_folder?: string
}
</script>

<style scoped>
.selector-card {
  container-type: inline-size;
  container-name: lora-selector;
}

.header-container {
  display: flex;
  flex-direction: column;
}

.header-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
}

/* 文件夹筛选器样式 */
.folder-filters {
  margin-bottom: 15px;
  width: 100%;
  background-color: var(--el-fill-color-light);
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.folder-level {
  display: flex;
  align-items: flex-start;
  margin-bottom: 12px;
}

.level-label {
  min-width: 70px;
  font-weight: bold;
  padding-top: 8px;
  font-size: 14px;
}

.folder-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  flex: 1;
}

.folder-tag {
  cursor: pointer;
  transition: all 0.3s ease;
  padding: 8px 15px;
  border-radius: 20px;
  font-size: 14px;

  &:hover {
    opacity: 0.9;
    transform: translateY(-2px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  }
}

.folder-count {
  margin-left: 4px;
  font-size: 0.85em;
  opacity: 0.8;
}

.current-filters {
  margin-top: 10px;
  display: flex;
  justify-content: flex-end;
}

/* Lora选择器选项样式 */
.option-item {
  padding: 8px 12px;
}

.option-thumbnail {
  width: 30px;
  height: 30px;
  margin-right: 12px;
}

.option-text {
  flex: 1;
}

.mr5 {
  margin-right: 5px;
}

/* Lora列表样式 */
.lora-list-container {
  margin-top: 20px;
}

.list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.list-title {
  font-size: 16px;
  font-weight: bold;
}

.list-count {
  font-size: 14px;
  color: var(--el-text-color-secondary);
}

.empty-list {
  padding: 40px 0;
  text-align: center;
  background-color: var(--el-fill-color-lighter);
  border-radius: 8px;
}

.lora-items {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.lora-item {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}

.item-name {
  font-weight: bold;
  max-width: 200px;
}

.lora-controls {
  flex: 1;
  margin-left: 20px;
  display: flex;
  flex-direction: column;
}

.strength-controls {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  margin-bottom: 20px;
}

.control-group {
  display: flex;
  flex-direction: column;
}

.control-label {
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--el-text-color-regular);
}

.tags-section {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.action-buttons {
  display: flex;
  gap: 5px;
}

/* 元数据弹窗样式 */
.metadata-container {
  padding: 15px;
}

.metadata-section {
  margin-bottom: 20px;
}

.tag-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
  padding: 10px;
  background-color: var(--el-fill-color-lighter);
  border-radius: 8px;
}

.tag-item {
  padding: 4px 8px;
  border-radius: 4px;
  transition: all 0.3s ease;
  cursor: default;
  background-color: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
}

.tag-frequency {
  font-size: 0.8em;
  margin-left: 4px;
  opacity: 0.7;
}

.tag-selection {
  margin-top: 20px;
}

.preview-container {
  text-align: center;
}

.no-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 150px;
  color: var(--el-text-color-placeholder);
  background-color: var(--el-fill-color-lighter);
  border-radius: 4px;

  .el-icon {
    margin-bottom: 10px;
  }
}

.lora-info {
  margin-top: 15px;
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 4px;
  text-align: left;

  &>div {
    margin-bottom: 8px;
  }
}

.config-section {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.config-controls {
  display: flex;
  gap: 20px;
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 8px;
}

.control-group {
  display: flex;
  flex-direction: column;
  gap: 5px;
  flex: 1;
}

.config-tags {
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 8px;
}

.tags-label {
  margin-bottom: 8px;
  display: inline-block;
}

.other-configs {
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 8px;
}

.other-configs-label {
  margin-bottom: 8px;
  display: inline-block;
}

.config-json {
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: monospace;
  font-size: 13px;
  color: var(--el-text-color-regular);
  max-height: 200px;
  overflow: auto;
  padding: 10px;
  background-color: var(--el-fill-color-lighter);
  border-radius: 4px;
}

.config-actions {
  display: flex;
  justify-content: flex-end;
  padding: 10px 0;
}

@media (max-width: 768px) {
  .header-top {
    flex-direction: column;
    align-items: flex-start;
  }

  .header-top .el-button {
    margin-top: 10px;
    align-self: flex-end;
  }

  .lora-controls {
    margin-left: 0;
    margin-top: 15px;
  }

  .lora-item .el-card__body {
    flex-direction: column;
  }
}

.lora-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
}

.lora-card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--el-border-color-light);
}

.item-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: bold;
}

.card-content {
  display: flex;
  flex-direction: column;
  padding: 10px 0;
}

.image-section {
  margin-bottom: 5px;
  display: flex;
  gap: 5px;
}

.lora-image {
  max-width: 100px;
  width: auto;
  object-fit: contain;
  border-radius: 4px;
  background-color: var(--el-fill-color-lighter);
}

.controls-section {
  display: flex;
  flex-direction: column;
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 8px;
}

.strength-controls {
  display: flex;
  justify-content: space-around;
  gap: 5px;
}

.control-item {
  width: 100px;
}

.action-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  justify-content: center;
}

.action-btn {
  flex: 1;
  min-width: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tags-section {
  flex: 1;
}

.tags-input {
  width: 100%;
}

.tag-long-text {
  max-width: 200px; /* 根据需求调整最大宽度 */
  white-space: nowrap; /* 强制单行显示 */
  overflow: hidden; /* 隐藏超出部分 */
  text-overflow: ellipsis; /* 显示省略号 */
  padding: 0 8px; /* 适当调整内边距 */
}

/* 响应式调整 */
@container (max-width: 768px) {
  .lora-grid {
    grid-template-columns: 1fr;
  }

  .action-buttons {
    flex-direction: column;
  }

  .action-btn {
    width: 100%;
  }
}

@container (min-width: 1200px) {
  .lora-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}
</style>
